/**  
 * @Title: SubTask.java
 * @Description: TODO(描述)
 * @author liuyi
 * @date 2023-08-04 22:31:09 
 */  
package com.fsxgt.datagrid.core.task;

import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;

import com.fsxgt.datagrid.core.exception.DataGridException;
import com.fsxgt.datagrid.core.utils.LogHelpper;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**  
 * @ClassName: SubTask
 * @Description: TODO(描述)
 * @author liuyi
 * @date 2023-08-04 22:31:09 
*/
@Data
@Slf4j
public abstract  class SubTask {
	

	private List<SubTask> children=new Vector<SubTask>();
	private int parentSize=0;
	private volatile int skipSize=0;
	private volatile CountDownLatch countDownLatch = null;
	private volatile Boolean isCancel=null;
	private String id;
	private String name;
	private Task task;
	
	public void init(Task task) {
		this.setTask(task);
	}
	
	public void addChild(SubTask subTask) {
		children.add(subTask);
		subTask.parentSize=subTask.parentSize+1;
	}

	public SubTask(String id,String name) {
		this.name=name;
		this.id=id;
	}
	
	public abstract  TaskReturn handler(TaskContext context) throws Exception;
	public abstract  void stopHandler(TaskContext context) throws Exception ;
	
	public void resetStatus() {
		
		isCancel=false;
		countDownLatch=null;
		skipSize=0;
		
	}
	
	public synchronized boolean getIsCancel() {
		
		return isCancel;
		
	}
	
	public synchronized void cancel() {

		this.isCancel=true;
		
		if(countDownLatch!=null) {
			//已经有线程进入
			countDownLatch.countDown();
		}else {
			//无线程进入
			task.countDown();
		}
		
		cancelChildren();

	}
	

	public synchronized void skip(String parentId) {

		if(countDownLatch!=null) {
			//已经有线程进入
			countDownLatch.countDown();
			
		}else {
			//无线程进入
			if(++skipSize==parentSize) {
				for(SubTask subTask:children) {
					subTask.skip(id);
				}
				task.countDown();
				
			}
		}
		
	}
	
	public  void start(TaskRunParam taskRunParam,TaskContext context) {
		
		if(getIsCancel()) {
			//退出状态时，有其他线程进入
			if(countDownLatch!=null) {
				countDownLatch.countDown();
			}
			return;
		}
		
		int size=0;
		
		synchronized(this) {
			
			size=parentSize-skipSize;	
			
			if(size>1&&countDownLatch==null) {
				//第一次访问
				countDownLatch=new CountDownLatch(size);
				countDownLatch.countDown();
				
			}else if(countDownLatch!=null){
				countDownLatch.countDown();
				return;
			}
		}
		

		try {
			task.getPool().execute(new Runnable() {
				@Override
				public void run() {
					try {
						if(countDownLatch!=null) {
							countDownLatch.await();
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						task.countDown();
						cancelChildren();
						return;
					}

					if(getIsCancel()) {
						task.countDown();
						return;
					}

					TaskReturn taskReturn=execute(taskRunParam, task,context);
					task.countDown();
					if(taskReturn!=null&&taskReturn.isContinue()) {
						List<String> route = taskReturn.getRoute();
						executeChildren(taskRunParam,context,route);
					}else {
						cancelChildren();
					}
				}
			});
		}catch(Throwable e) {
			task.addException(this.getId(), e);
			task.countDown();
			cancelChildren();
		}
		
		
	}
	
	private void cancelChildren() {
		//执行children
		for(SubTask subTask:children) {
			subTask.cancel();
		}
	}
	
	public void executeChildren(TaskRunParam taskRunParam,TaskContext context,List<String> route) {
		//执行children
		if(route==null) {
			for(SubTask subTask:children) {
				subTask.start(taskRunParam,context);
			}
		}else {
			for(SubTask subTask:children) {
				if(route.contains(subTask.getId())) {
					subTask.start(taskRunParam,context);
				}else {
					subTask.skip(this.id);
				}
			}
		}
		
	}
	
	
	public TaskReturn execute(TaskRunParam taskRunParam,Task task,TaskContext context) {

		long cur = System.currentTimeMillis();
		
		try {
			task.acquire();
			
			cur = System.currentTimeMillis();
			
			LogHelpper.setLogFileName(taskRunParam.getLogFileName());
	
			
			StatusHelper.record(this,null,StatusHelper.BEGIN);
			
			//调用组件
			
			Integer retryCount = (taskRunParam.getRetryCount()==null||taskRunParam.getRetryCount()<0)?0:taskRunParam.getRetryCount();
			
			TaskReturn result = null;
			
		
			
			for(int i=0;i<=retryCount;i++) {
				try {
					result=this.handler(context);
					break;
				}catch(InterruptedException e) {
					throw e;
				}catch(Throwable e) {
					if(i+1>retryCount) {
						throw e;
					}else {
						log.error("",e);
						StatusHelper.record(this, String.format("执行失败,重试第%d次", i+1));
					}
				}
			}
			
			StatusHelper.record(this,String.format("用时:%s毫秒", System.currentTimeMillis()-cur),StatusHelper.END);
			
			return result;
			
		}catch (InterruptedException e) {
			// TODO Auto-generated catch block
			task.addException(this.getId(), new DataGridException("被强制终止"));
			try {
				this.stopHandler(context);
				StatusHelper.record(this,"被强制终止",StatusHelper.INTERRUPTED);
			}catch(Exception e1) {
				task.addException(this.getId(), e1);
				StatusHelper.record(this,"强制终止失败",StatusHelper.INTERRUPTEDERROR);
			}
		}catch(Throwable e){
			StatusHelper.record(this,String.format("异常,用时:%s毫秒", System.currentTimeMillis()-cur),StatusHelper.ERROR);
			task.addException(this.getId(), e);
		}finally {
			task.release();
			LogHelpper.clearLogFileName();
		}
		

		return null;
		
	}
	
}
